package sim.core;

import java.awt.*;

/**
 * 
 * This is the base class for creating asynchronous tasks in the simulator.
 * 
 * Typically this class will be used to create anonymous classes by overriding run() to
 * place the code to be executed at given time in the future.
 *
 * By default, tasks execute only once. They can be re-scheduled (within run()) to execute
 * again at a later time.
 * 
 * Tasks can also be canceled to prevent them from executing.
 * 
 * Tasks are executed according to <b>simulation time</b>.
 * 
 * @author smd
 *
 */
public class Task implements Runnable, Comparable<Task>, Displayable {
    
    double due ;
    Object owner ;
    protected boolean isQueued = false ;
    protected boolean isCancelled = false ; 
    protected boolean reScheduled = false ;

    private int seqN = g_seqN++ ;
    private static int g_seqN = 0 ;

    /**
     * Creates an anonymous Task to execute "immediately".
     * The task will execute once, but 
     * can be re-scheduled to execute again at a given later time.
     */
    public Task() {
    	this(0) ;
    }
    
    /**
     * Creates an anonymous Task.
     * By default it executes once, when it is due.
     * Can be re-scheduled to execute again at a given later time.
     * 
     * @param due Number of seconds to wait until the task executes. 
     */
    public Task( double due ) {
    	this( null, due ) ;
    }

    /**
     * Creates an new Task.
     * By default it executes once, when it is due.
     * Can be re-scheduled to execute again at a given later time.
     * 
     * @param owner - Owner of the task (typically a node).
     * @param due Number of seconds to wait until the task executes. 
     */
    public Task( Object owner, double due ) {
    	this.owner = owner ;
    	Scheduler.schedule( this, due) ;
    }

   
    /* (non-Javadoc)
     * 
     * This method should overriden in all concrete subtypes of this base class.
     * @see java.lang.Runnable#run()
     */
    public void run() {
    	System.err.println("Unexpected execution of Task.run() method.") ;
    	System.err.println("Override public void run() in parent class...") ;
    }
    
    public void cancel() {
    	isCancelled = true ;
    	reScheduled = false ;
    }
        
    void reset() {
    	isQueued = false ;
    	reScheduled = false ;
    }
    
    public void reSchedule() {
    }
    
    public void reSchedule( double t ) {
    	Scheduler.reSchedule( this, t ) ;
    	reScheduled = true ;
    }

    public int hashCode() {
    	return seqN ;
    }
    
    public boolean equals( Object other ) {
    	return other != null && equals( (Task) other ) ;
    }
    
    public boolean equals( Task other ) {
    	return other != null && this.seqN == other.seqN ;
    }
    
    public int compareTo(Task other) {
    	if( this.due == other.due ) return (this.seqN - other.seqN) ;
    	else return this.due < other.due ? -1 : 1 ;
    }
  
    public String toString() {
        return due + " " + seqN ;
    }
        
    public void display(Graphics2D gu, Graphics2D gs) {}
}

